
#include "mod_man.h"

void* __stdcall get_mod_var(lua_State *Ll,char *var,int var_type){
	int res;
	int vt=0;
//	printf("in get_mod_var with %s (type %d)\n",var,(char)var_type);

//	res=getLuaVar(L,var,0);
//	printf("\tvariable = %d\n",res);

	if(((char)var_type)==0xff)
		vt=0;
	else if((var_type&0x87)==0x80)
		vt=5;
	else if(var_type&0x40)
		vt=4;
	else if((var_type&7)<7)
		vt=1;
	else if((var_type&7)==7)
		vt=2;

	return getLuaVar(L,var,vt);
}


void __stdcall set_mod_var(lua_State *Ll,char *var,int var_type){
	char vt=(char)var_type;
	int v;
	long double r;

	__asm{ mov v,eax}
//	if(vt&0x20)
	{
	 	char *tmp_var_name;
		int status;

//		printf("in set_mod_var with %s=%d\n",var,v);

		tmp_var_name=getMem_C(0x1000);

		if((vt&0xcf)==0x80){
			__asm{ fstp r }
			sprintf(tmp_var_name,"%s=%.32g;\n",var,r);
		}else if((vt&7)==7)
			sprintf(tmp_var_name,"%s=[[%s]];",var,v);
		else
			sprintf(tmp_var_name,"%s=%d;",var,v);

		if( status=luaL_loadstring(L,tmp_var_name)){
			report(L,status);
		}else
			report(L, docall(L,0,0));

//		status=luaL_loadstring(L,tmp_var_name)||docall(L,0,0);
//		/*printf("status = %xh\n",*/report(L,status)/*)*/;

		freeMem_C(tmp_var_name);
	}
}

void* __stdcall call_mod_func(lua_State *Ll,char *func,int n_par){
//	printf("in call_mod_func with %s\n",func);

//	if(vt&0x20)
	{
//	 	char *tmp_var_name;
		int status;

//		tmp_var_name=getMem_C(4*1024);

		if( status=luaL_loadstring(L,func)){
			report(L,status);
		}else
			report(L, docall(L,0,0) );

//		status=luaL_loadstring(L,func)||docall(L,0,0);
//		/*printf("status = %xh\n",*/report(L,status)/*)*/;
	}
	return 0;
}


void* getLuaVar_C(lua_State *L,char *var_name,int type){
	return getLuaVar(L,var_name,type);
}
void setLuaVar_C(lua_State *L,char *var_name,int type,void *v){
	setLuaVar(L,var_name,type,v);
}

/*
typedef void *(*fnc)();

extern fnc fncs[]={
	getMem_C,
	regetMem_C,
	freeMem_C,
	cpyMem_C,
	sizeMem_C,

	getLuaVar_C,	//varName,type
	setLuaVar_C,	//varName,type

	NULL
};

extern int fncs_size=(sizeof(fncs)/sizeof(fnc))-1;
*/

extern char * __stdcall get_mod_memb_name(void *lpMod_memb);
extern char * __stdcall get_mod_memb_doc(void *lpMod_memb);
extern void __stdcall get_mod_memb_type(void *lpMod_memb,char *sztype);
extern void __stdcall get_mod_memb_access(void *lpMod_memb,char *sztype);
extern int __stdcall get_mod_memb_val(void *lpMod_memb,void **val);
extern int __stdcall get_mod_memb_lppars_bin(void *lpMod_memb,void **pars);
extern int __stdcall get_mod_memb_lprets_bin(void *lpMod_memb,void **rets);

int Lmod_memb_index(lua_State *L){
	int z;
	char *s;
	void **modmemb;
	int t=lua_type(L,2);

	modmemb=lua_touserdata(L,1);

	if(t==LUA_TNUMBER){
/*
		z=lua_tonumber(L,2);
		mod=get_mod_memb_idx(modmemb,z);
		if(!mod)
			return 0;
		lua_pushlightuserdata(L,modmemb);
		lua_newtable(L);
			lua_pushstring(L,sz__index);
			lua_pushcfunction(L,Lmod_index);
			lua_rawset(L,-3);
		lua_setmetatable(L,-2);
		return 1;
*/
	}else if(t==LUA_TSTRING){
		s=lua_tostring(L,2);
		if(!strcmp(s,szName)){
			lua_pushstring(L,get_mod_memb_name(*modmemb));
			return 1;
		}else if(!strcmp(s,szComment)){
			lua_pushstring(L,get_mod_memb_doc(*modmemb));
			return 1;
		}else if(!strcmp(s,szType)){
			char tp[255];
			get_mod_memb_type(*modmemb,tp);
			lua_pushstring(L,tp);
			return 1;
		}else if(!strcmp(s,"access")){
			char tp[20];
			get_mod_memb_access(*modmemb,tp);
			lua_pushstring(L,tp);
			return 1;
		}else if(!strcmp(s,"val")){
			void *lpval;
			z=get_mod_memb_val(*modmemb,&lpval);
			z&=0xc7;
			switch(z){
				case 0:
					lua_pushnil(L);
				case 0x80:
					if(lpval)
						lua_pushnumber(L,*((double*)lpval));
					else
						lua_pushnil(L);
					break;
				case 0x7:
				case 0x87:
					lua_pushstring(L,((char*)lpval));
					break;
				default:
					lua_pushnumber(L,*((int*)lpval));
			}
			return 1;
//		}else if(!strcmp(s,)){
//		}else if(!strcmp(s,)){
//		}else if(!strcmp(s,)){
		}

		return 0;
	}
}

int Lmod_memb_newindex(lua_State *L){
	int z;
	char *s;
	void **modmemb;
	void *lpval;
	double v;
	int t=lua_type(L,2);

	modmemb=lua_touserdata(L,1);

	if(t==LUA_TNUMBER){

	}else if(t==LUA_TSTRING){
		s=lua_tostring(L,2);
		if(!strcmp(s,"val")){

			z=get_mod_memb_val(*modmemb,&lpval);
			z&=0xc7;
			switch(z){
				case 0:
					break;
				case 0x80:
					v=lua_tonumber(L,3);
					if(lpval)
						*((double*)lpval) = (double)v;
					break;
				case 0x7:
				case 0x87:
					if(lpval)
						lstrcpy((char*)lpval,
								lua_tostring(L,3));
					break;
				default:
					v=lua_tonumber(L,3);
					*((unsigned int*)lpval) = (unsigned int)v;
			}
			return 0;
//		}else if(!strcmp(s,)){
//		}else if(!strcmp(s,)){
		}
	}
	return 0;
}


struct Rets{
	unsigned saved_ebp;
	struct Rets* prev;
};


#pragma optimize( "", off )

/*__declspec(thread)*/ struct Rets* rets = 0;

int Lmod_memb_call(lua_State *L){
	int z,i;
	void **modmemb;
	void *lpval;
	char *lppars;
	char *vs;
	double vr;
	int vi;
	void **vu;
	int ri;
	unsigned saved_esp;
	struct Rets saved;
	char c;
	int t = lua_type(L,1);

	modmemb=lua_touserdata(L,1);

	z=get_mod_memb_val(*modmemb,&lpval);
	if(!(z&0xc7)){
/*
		__asm{
			lea eax,[old_ebp_restore+1]
			mov saved_esp,eax
		}
		VirtualProtect(saved_esp & (~(0x1000-1)), 0x1000-2, PAGE_EXECUTE_READWRITE	, &saved_esp);
*/
		z=get_mod_memb_lppars_bin(*modmemb,&lppars);
		lppars += z-1;

		__asm{
			pusha
			mov saved_esp,esp
		}
		saved.prev = rets;
		rets = &saved;
		__asm{
			lea eax,[saved]
			mov [eax],ebp
		}

	// set SEH b
		__asm{
			call mmc_set_SEH_handler

			mov esp,[esp+8]
			jmp mmc_error_in_foo
		}
	mmc_set_SEH_handler:
		__asm{
			xor eax,eax
			push dword ptr fs:[eax]
			mov fs:[eax],esp
		}
	// set SEH e

		for(i = z+1; z; lppars--, z--, i--){
			c=*lppars;
			switch(c&0xc7){
				case 0x80:
					vr=lua_tonumber(L,i);
					__asm{
						push eax
						push eax
						fld vr
						fstp qword ptr [esp]
					}
					break;
				case 0x7:
				case 0x87:
					vs=lua_tostring(L,i);
					__asm{
						push vs
					}
					break;
				default:
					switch(lua_type(L,i)){
						case LUA_TNIL:
							__asm{
								push 0
							}
							break;
						case LUA_TUSERDATA:
							vu=lua_touserdata(L,i);
							__asm{
								mov eax,vu
								push dword ptr [eax]
							}
							break;
						case LUA_TLIGHTUSERDATA:
							vu=lua_touserdata(L,i);
							__asm{
								push vu
							}
							break;
						case LUA_TSTRING:
							vs=lua_tostring(L,i);
							__asm{
								push vs
							}
							break;
						default:
							vi=(int)lua_tonumber(L,i);
							__asm{
								push vi
							}
					}
			}
		}
//		saved.prev = rets;
//		rets = &saved;
////int 3
//		__asm{
//			lea eax,[saved]
//			mov [eax],ebp
		__asm{
			call lpval
		}
	old_ebp_restore:
	// SEH reset b
		__asm{
			mov ebp,eax
			
			xor eax,eax
			pop dword ptr fs:[eax]
			pop eax

			mov eax,ebp
		}
	// SEH reset e

		__asm{
			mov ebp,rets
			mov ebp,ds:[ebp]
			mov esp,saved_esp
			mov ri,eax
			popa
		}
		rets = saved.prev;
		z=get_mod_memb_lprets_bin(*modmemb,&lppars);
		if(z == 0 || lppars == 0)
			lua_pushnil(L);
		else{
			c = *lppars;
			switch(c){
				case 0x87:
				case 0x7:
					if(ri == 0)
						lua_pushnil(L);
					else
						lua_pushstring(L, (char*)ri);
					break;
				default:
					lua_pushnumber(L, (double)ri);
			}
		}
		return 1;
	}
	return 0;

	mmc_error_in_foo:
		Error("Error! exception is occured inside asm module call\n");
		__asm{
			mov eax,-1
		}
		goto old_ebp_restore;
}

#pragma optimize( "", on )



extern char * __stdcall get_mod_name(void *lpMod_link);
extern char * __stdcall get_mod_doc(void *lpMod_link);
extern void * __stdcall get_mod_func(void *lpMod_link);
extern char * __stdcall get_module_src(void *lpMod_link);
extern void * __stdcall get_mod_memb_idx(void *lpMod_link,int idx);
extern void * __stdcall get_mod_memb_by_name(void *lpMod_link,char *lpszModMembName);

int Lmod_memb_by_name(lua_State *L){
	char *s;
	void **mod;
	void **p;
	int t=lua_type(L,2);

	if(t==LUA_TSTRING){
		s=lua_tostring(L,2);
		mod=lua_touserdata(L,1);
		mod=get_mod_memb_by_name(*mod,s);
		if(mod){
			p=lua_newuserdata(L,sizeof(void**));
			*p=mod;
//			lua_pushlightuserdata(L,mod);
			lua_newtable(L);
				lua_pushstring(L,sz__index);
				lua_pushcfunction(L,Lmod_memb_index);
				lua_rawset(L,-3);
				
				lua_pushstring(L,sz__call);
				lua_pushcfunction(L,Lmod_memb_call);
				lua_rawset(L,-3);
				
				lua_pushstring(L,sz__newindex);
				lua_pushcfunction(L,Lmod_memb_newindex);
				lua_rawset(L,-3);
			lua_setmetatable(L,-2);
			return 1;
		}
	}
	return 0;
}

int Lmod_index(lua_State *L){
	int z;
	char *s;
	void **mod,*mmemb,**p;
	int t=lua_type(L,2);

	mod=lua_touserdata(L,1);

	if(t==LUA_TNUMBER){
		z=lua_tonumber(L,2);
		mmemb=get_mod_memb_idx(*mod,z);
		if(!mmemb)
			return 0;
		mod=lua_newuserdata(L,sizeof(void**));
		*mod=mmemb;
//		lua_pushlightuserdata(L,mmemb);
		lua_newtable(L);
			lua_pushstring(L,sz__index);
			lua_pushcfunction(L,Lmod_memb_index);
			lua_rawset(L,-3);
				
			lua_pushstring(L,sz__call);
			lua_pushcfunction(L,Lmod_memb_call);
			lua_rawset(L,-3);
				
			lua_pushstring(L,sz__newindex);
			lua_pushcfunction(L,Lmod_memb_newindex);
			lua_rawset(L,-3);
		lua_setmetatable(L,-2);
		return 1;
	}else if(t==LUA_TSTRING){
		s=lua_tostring(L,2);
		if(!strcmp(s,szName)){
			lua_pushstring(L,get_mod_name(*mod));
			return 1;
		}else if(!strcmp(s,szComment)){
			lua_pushstring(L,get_mod_doc(*mod));
			return 1;
		}else if(!strcmp(s,"byname")){
//			lua_pushlightuserdata(L,0);
			p=lua_newuserdata(L,sizeof(void**));
			*p=*mod;
			lua_newtable(L);
				lua_pushstring(L,sz__index);
				lua_pushcfunction(L,Lmod_memb_by_name);
				lua_rawset(L,-3);
			lua_setmetatable(L,-2);
			return 1;
		}else if(!strcmp(s,szFunc)){
			lua_pushcfunction(L,get_mod_func(*mod));
			return 1;
		}else if(!strcmp(s,szSrc)){
			lua_pushstring(L,get_module_src(*mod));
			return 1;
//		}else if(!strcmp(s,)){
//		}else if(!strcmp(s,)){
//		}else if(!strcmp(s,)){
//		}else if(!strcmp(s,)){
//		}else if(!strcmp(s,)){
		}

		return 0;
	}
}

extern void * __stdcall get_mod_by_idx(int idx);
extern void * __stdcall get_mod_by_name(char *lpszModName);
extern int __stdcall get_mods_num();

int Lmodule_by_name(lua_State *L){
	char *s;
	void *mod;
	void **p;
	int t=lua_type(L,2);

	if(t==LUA_TSTRING){
		s=lua_tostring(L,2);
		mod=get_mod_by_name(s);
		if(mod){
			p=lua_newuserdata(L,sizeof(void**));
			*p=mod;
//			lua_pushlightuserdata(L,mod);
			lua_newtable(L);
				lua_pushstring(L,sz__index);
				lua_pushcfunction(L,Lmod_index);
				lua_rawset(L,-3);
			lua_setmetatable(L,-2);
			return 1;
		}
	}
	return 0;
}

int Lmodules_index(lua_State *L){
	int z;
	char *s;
	void *res;
	void **p;
	int t=lua_type(L,2);

	if(t==LUA_TNUMBER){
		z=lua_tonumber(L,2);
		res=get_mod_by_idx(z);
		if(!res)
			return 0;
		p=lua_newuserdata(L,sizeof(void**));
		*p=res;
//		lua_pushlightuserdata(L,res);
		lua_newtable(L);
			lua_pushstring(L,sz__index);
			lua_pushcfunction(L,Lmod_index);
			lua_rawset(L,-3);
		lua_setmetatable(L,-2);
		return 1;
	}else if(t==LUA_TSTRING){
		s=lua_tostring(L,2);
		if(!strcmp(s,"n")){
			lua_pushnumber(L,get_mods_num());
			return 1;
		}else if(!strcmp(s,"byname")){
//			lua_pushlightuserdata(L,0);
			lua_newuserdata(L,0);
			lua_newtable(L);
				lua_pushstring(L,sz__index);
				lua_pushcfunction(L,Lmodule_by_name);
				lua_rawset(L,-3);
			lua_setmetatable(L,-2);
			return 1;
		}
		return 0;
	}
}

int modules_init(lua_State *L){
	lua_pushstring(L,"modules");
	lua_newtable(L);

	lua_newtable(L);
		lua_pushstring(L,sz__index);
		lua_pushcfunction(L,Lmodules_index);
		lua_rawset(L,-3);
	lua_setmetatable(L,-2);

	lua_rawset(L,LUA_GLOBALSINDEX);

	return 0;
}

